'use strict';

Object.defineProperty(exports, "__esModule", {
	value: true
});
exports.default = functmpl;

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _scope = require('./scope');

var _scope2 = _interopRequireDefault(_scope);

var _script = require('./script');

var _script2 = _interopRequireDefault(_script);

var _func = require('./func');

var _func2 = _interopRequireDefault(_func);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const Scope = _scope2.default;
const Script = _script2.default;
const useType = {
	include: Symbol(),
	echo: Symbol(),
	text: Symbol()
};
const useTypeSet = new Set([useType.include, useType.echo, useType.text]);

const symbol = {
	CONTINUE: Symbol(),
	BREAK: Symbol()
};
const next = _ => next;
let nameRegExp = /^[a-zA-Z0-9_\-\~\!\@\#\$\*]+$/;

/**
 * 模板类
 * 
 * @attribute	{String}	filename	文件名
 * @readOnly	{String}	status		状态
 * @readOnly	{Object}	functmpl	原生的functmpl获取函数
 * @readOnly	{Object}	useType		可用类型
 * @readOnly	{Object}	symbol		符号猎豹
 * @readOnly	{Object}	scope		作用域类
 * @readOnly	{Object}	script		脚本类
 * 
 * @function	@async	setTemplate(text)					设置模板
 * @function	@async	loadFile(filename)					加载模板文件
 * @function			use(func, funcType)					添加处理函数
 * @function	@async	parse(...param)						解析数据到模板
 * @function	@async	parseList(list, scope)				解析列表
 * @function	@async	parseNode(node, scope)				解析节点
 * @function	@async	repeat(list, scope, data, options)	将列表重复执行
 * 
 * @attribute	{String}	_status		状态
 * @attribute	{String}	_filename	文件名
 * @attribute	{String}	_template	
 * @attribute	{String}	_path		
 * @attribute	{Functmpl}	_parent		
 * @attribute	{Array}		_func		功能函数列表
 * @attribute	{Array}		_include	
 * @attribute	{Array}		_echo		
 * @attribute	{Array}		_text		
 * @attribute	{Array}		_script		
 * @attribute	{Array}		_sentence	
 */
class Functmpl {
	/**
  * 构造函数
  * @param  {Functmpl} parent 父模板
  */
	constructor(parent) {
		this._status = 'new';
		this._filename = '';
		this._template = '';
		this._path = '';
		if (parent && parent instanceof Functmpl) {
			this._parent = parent;
			this._func = parent._func;
			this._include = parent._include;
			this._echo = parent._echo;
			this._text = parent._text;
			this._path = parent._path;
			this._script = parent._script;
			this._sentence = parent._sentence;
		} else {
			this._parent = null;
			this._func = [];
			this._include = [];
			this._echo = [];
			this._text = [];
			this._script = [];
			this._sentence = [];
			if (parent && typeof parent.path === "string") {
				this._path = parent.path;
			}
		}
	}

	get functmpl() {
		return functmpl;
	}
	get useType() {
		return useType;
	}
	get symbol() {
		return symbol;
	}
	get scope() {
		return _scope2.default;
	}
	get script() {
		return _script2.default;
	}

	/**
  * 设置文件名
  * @param  {String} name 文件名
  * @throw {Error} 如果设置失败
  */
	set filename(name) {
		if (!(this._status === 'new' || this._status === 'error' || this._status === 'wait')) {
			throw new Error("File is Loading or template is parsing!");
		}
		this._filename = name;
	}
	/**
  * 获取文件名
  * @return {String} 文件名
  */
	get filename() {
		return this._filename;
	}

	/**
  * 获取当前状态
  * @return {String} 状态
  */
	get status() {
		return this._status;
	}

	/**
  * 设置模板
  * @param  {String} text 模板文本
  * @throw {Error} 如果设置失败
  */
	async setTemplate(text) {
		if (!(this._status === 'new' || this._status === 'error' || this._status === 'wait')) {
			throw new Error("File is Loading or template is parsing!");
		}
		try {
			this._template = parse(text);
			this._status = 'wait';
		} catch (e) {
			this._status = 'error';
			throw e;
		}
	}

	/**
  * 加载模板文件
  * @param  {String} filename 模板文件名
  * @throw {Error} 如果设置或加载失败
  */
	async loadFile(filename) {
		if (!(this._status === 'new' || this._status === 'error' || this._status === 'wait')) {
			throw new Error("File is Loading or template is parsing!");
		}
		this._status = 'loading';
		this._filename = filename;
		filename = joinPath(this._path, filename);
		let data;
		try {
			data = await getFile(filename);
			this._template = parse(data);
			this._status = 'wait';
		} catch (e) {
			this._status = 'error';
			throw e;
		}
	}

	/**
  * 添加处理函数
  * @param  {Function} func 中间件
  * @param  {String | Symbol} type 处理内容
  * @return {Undefined}      undefined
  */
	use(func, funcType) {
		let funcs;
		//假定输入为数组
		if (func instanceof Array) {
			funcs = func;
		} else {
			funcs = [func];
		}
		//处理并过滤出普通函数
		funcs = funcs.map(f => {
			if (typeof f === 'function') {
				//普通函数
				return f;
			} else if (typeof f === 'object') {
				//对象
				let { type: funcType, func } = f;
				//功能函数判断
				if (typeof func !== 'function') {
					return;
				}
				//类型判断
				if (typeof funcType === "string") {
					//字符串则转为正则表达式
					funcType = new RegExp('^' + funcType + '$');
				} else if (!(funcType instanceof RegExp || useTypeSet.has(funcType))) {
					//类型既不是字符串、正则表达式，也不是特殊类型，则当做普通函数处理
					return func;
				}
				//根据类型处理，并直接加入函数列表
				switch (funcType) {
					case useType.include:
						this._include.push(func);
						break;
					case useType.echo:
						this._echo.push(func);
						break;
					case useType.text:
						this._text.push(func);
						break;
					default:
						this._func.push({ type: funcType, func });
						break;
				}
			}
		}).filter(f => f);
		//已经无函数则返回
		if (funcs.length === 0) {
			return;
		}
		//根据类型获取默认列表
		//符号标示特殊的处理单元
		//字符串或正则表达式标示特定匹配的功能
		//其他标示任意的功能
		let list;
		switch (funcType) {
			case useType.include:
				list = this._include;
				break;
			case useType.echo:
				list = this._echo;
				break;
			case useType.text:
				list = this._text;
				break;
			default:
				list = this._func;
				if (typeof funcType === "string") {
					funcType = new RegExp('^' + funcType + '$');
				} else if (!(funcType instanceof RegExp)) {
					funcType = new RegExp();
				}
				funcs = funcs.map(func => ({ func, type: funcType }));
		}
		funcs.forEach(f => list.push(f));
	}

	/**
  * 解析
  * @param  {...Object} param 传入的作用域或数值
  * @return {String}          解析后文本
  */
	async parse(...param) {
		const ftl = this;
		if (ftl._status !== 'wait') {
			return null;
		}
		ftl._status = 'parsing';
		//作用域父对象
		let s = [];
		//主作用域
		let scope;
		param.forEach(p => {
			if (Scope.is(p) && !scope) {
				return scope = p;
			}
			s.push(p);
		});
		scope = Scope(scope);
		s.forEach(v => {
			for (let k in v) {
				scope[Scope.create](k, v[k]);
			}
		});
		//创建执行时this
		const that = Object.create(ftl);
		//返回值
		let ret = "";
		//输出函数
		that.echo = t => {
			ret += t;
		};
		await that.parseList(that._template, scope);
		return ret;
	}

	/**
  * 解析列表
  * @param {Array} 列表
  * @param {Scope} 作用域
  */
	async parseList(list, scope) {
		//对列表中项目尽心逐个解析
		for (let i = 0, l = list.length; i < l; i++) {
			await this.parseNode(list[i], scope);
		}
	}

	/**
  * 解析节点
  * @param {Object} 节点信息
  * @param {Scope} 作用域
  */
	async parseNode(node, scope) {
		//根据节点类型进行解析
		switch (node.type) {
			case 'func':
				{
					//标签名称，标签值，标签属性，子节点列表，子标签
					let { name, value, attr, list, sub } = node;
					let param = {};
					//标签值
					value = await value.get(scope);
					//参数列表
					for (let k in attr) {
						param[k] = await attr[k].get(scope);
					}
					//子标签
					for (let i = 0, l = sub.length; i < l; i++) {
						let node = sub[i];
						//子标签名称，子标签值，子标签属性，子节点列表
						let { name, value, attr, list } = node;
						let param = {};
						//子标签值
						value = await value.get(scope);
						//子标签参数列表
						for (let k in attr) {
							param[k] = await attr[k].get(scope);
						}
						//更新子标签信息
						sub[i] = { name, value, param, list };
					}
					return handle.call(this, { name, value, param, list, sub }, scope, this._func.filter(x => x.type.test(name)).map(({ func }) => func));
				}
			case 'include':
				//引入文件的前提是模板为确定的一个文件
				if (!this._filename) {
					return;
				}
				return handle.call(this, joinPath(this._filename, "../", (await node.value.exec(scope))), scope, this._include, baseInclude);
			case 'echo':
				return handle.call(this, node.value, scope, this._echo, async (t, s) => this.echo((await t.exec(s))));
			case 'text':
				return handle.call(this, node.value, scope, this._text, async t => this.echo(t));
			case 'script':
				return handle.call(this, node.value, scope, this._script, async (t, s) => t.exec(s));
			case 'sentence':
				return handle.call(this, node.value, scope, this._sentence);
		}
	}
	/**
  * 将列表重复执行
  * @param  {Array} list                 列表
  * @param  {Scope} scope                作用域
  * @param  {Object} data                重复数据
  * @param  {String} options.key         键保存的变量名
  * @param  {String} options.value       至保存的变量名
  * @param  {String} options.total       总数保存的变量名
  * @param  {String} options.num         总数保存的变量名（过时的，推荐用total）
  * @param  {Boolean} options.release    是否将值展开
  * @param  {Boolean} options.noBreak    是否不处理break
  * @param  {Boolean} options.noContinue 是否不处理continue
  * @param  {Object} options.base        将展开的基本数据
  */
	async repeat(list, scope, data, { key, value, total, num, release, noBreak, noContinue, base }) {
		//将要重复的项目列表
		let items = [];
		if (typeof data === "number") {
			//重复数据是数字，仅表示重复次数
			for (let i = 0; i < data; i++) {
				items.push({ key: i });
			}
			value = release = false;
		} else if (Array.isArray(data)) {
			//重复数据是数组
			//键为序号，从0开始
			//值为对应内容
			data.forEach((value, key) => items.push({ key, value }));
		} else if (data && typeof data === "object") {
			//重复数据是对象
			//键为对象的键
			//值为对象对应的内容
			for (let k in data) {
				items.push({ key: k, value: data[k] });
			}
		} else {
			//否则直接返回
			return;
		}
		if (typeof value !== "string") {
			value = "";
		}
		if (typeof key !== "string") {
			key = "";
		}
		if (!(total && typeof total === "string")) {
			total = typeof num === "string" ? num : "";
		}
		//循环处理
		for (let i = 0, l = items.length; i < l; i++) {
			try {
				let item = items[i];
				//获得子作用区域
				let childScope = Scope(scope);
				//键、值、总数的变量
				if (key) {
					childScope[Scope.create](key, item.key);
				}
				if (value) {
					childScope[Scope.create](value, item.value);
				}
				if (total) {
					childScope[Scope.create](total, l);
				}
				//展开值
				if (release && item.value && typeof item.value === 'object') {
					item = item.value;
					for (let k in item) {
						childScope[Scope.create](k, item[k]);
					}
				}
				//基本数据
				if (typeof base === 'object') {
					for (let k in base) {
						childScope[Scope.create](k, base[k]);
					}
				}
				//解析列表
				await this.parseList(list, childScope);
			} catch (sign) {
				//如果有信号
				if (sign === symbol.BREAK) {
					//break信号处理
					if (noBreak) {
						throw sign;
					}
					return;
				} else if (sign === symbol.CONTINUE) {
					//continue信号处理
					if (noContinue) {
						throw sign;
					}
				} else if (typeof sign === "object" && sign.type === symbol.BREAK) {
					//多层break信号处理
					if (noBreak) {
						throw sign;
					}
					if (!sign.number || sign.number <= 0) {
						return;
					}
					sign.number--;
					if (sign.number <= 0) {
						throw symbol.BREAK;
					}
					return;
				} else if (sign && sign.type === symbol.CONTINUE) {
					//多层continue信号处理
					if (noContinue) {
						throw sign;
					}
					if (sign.number > 0) {
						sign.number--;
						if (sign.number <= 0) {
							throw symbol.CONTINUE;
						}
						throw sign;
					}
				} else {
					//其他信号
					throw sign;
				}
			}
		}
	}
}

/**
 * 插入目录
 */
function joinPath(path, ...allname) {
	let name = allname.shift();
	path = path.replace(/([/\\]+)/g, '/').split('/');
	name = name.replace(/([/\\]+)/g, '/').split('/');
	if (!name[0]) {
		path = [];
	}
	while (name.length) {
		let p = name.shift();
		if (p === '..') {
			path.pop();
		} else if (p !== '.') {
			path.push(p);
		}
	}
	path = path.join("/");
	return allname.length ? joinPath(path, ...allname) : path;
}

/**
 * 深度复制对象
 * @param Object 被复制的对象
 * @return Object 复制产生的对象
 */
function deepCopy(source) {
	let result;
	let type = typeof source;
	if (type !== 'object' || source === null) {
		result = source;
	} else if (source instanceof Array) {
		result = [];
		for (let i = 0, l = source.length; i < l; i++) {
			result[i] = typeof source[i] === 'object' ? deepCopy(source[i]) : source[i];
		}
	} else {
		result = {};
		for (let k in source) {
			result[k] = typeof source[k] === 'object' ? deepCopy(source[k]) : source[k];
		}
	}
	return result;
}

/**
 * 节点处理
 * parseNode中使用
 * @param  {Any}				obj		处理的数据
 * @param  {Scope}				scope	作用域
 * @param  {Function[]}			list	处理函数列表
 * @param  {Function | null}	base	默认处理函数
 */
async function handle(obj, scope, list, base) {
	for (let i = 0, l = list.length; i < l; i++) {
		if (next !== (await list[i].call(this, obj, scope, next))) {
			return;
		}
	}
	if (base) {
		return base.call(this, obj, scope, next);
	}
}
/**
 * 默认包含函数
 * @param  {String} filename 文件名
 */
async function baseInclude(filename) {
	let f = new Functmpl(this);
	try {
		await f.loadFile(filename);
		return this.echo((await f.parse(_scope2.default)));
	} catch (e) {}
}
/**
 * 获取文件内容
 * @param {String} 文件名
 * @param {Function} 回调函数
 */
function getFile(fn) {
	return new Promise((a, b) => _fs2.default.readFile(fn, 'utf-8', (e, d) => e ? b(e) : a(d)));
}

/**
 * 解析
 * @param String 要解析的文本
 * @return Object 解析后的数据
 */
function parse(text) {
	//位置: 主位置, 引入, 功能, 子功能, 功能结束符, 语句, 表达式
	let index = 0,
	    include = 0,
	    func = 0,
	    subfunc = 0,
	    end = 0,
	    script = 0,
	    sentence = 0;
	//根, 当前位置
	let root = { list: [], main: null, sub: [] },
	    current = root;
	root.main = root;
	do {
		//首先查找各起点位置
		if (include !== -1) {
			include = text.indexOf("<#", index);
		}
		if (func !== -1) {
			func = text.indexOf("<@", index);
		}
		if (subfunc !== -1) {
			subfunc = text.indexOf("<|", index);
		}
		if (end !== -1) {
			end = text.indexOf("</>", index);
		}
		if (script !== -1) {
			script = text.indexOf("<`", index);
		}
		if (sentence !== -1) {
			sentence = text.indexOf("<%", index);
		}
		//选中的类型, 新的位置
		let type = '',
		    newindex = text.length;
		//找出最靠前的起点及类型
		if (include !== -1 && include < newindex) {
			newindex = include;
			type = 'include';
		}
		if (func !== -1 && func < newindex) {
			newindex = func;
			type = 'func';
		}
		if (subfunc !== -1 && subfunc < newindex) {
			newindex = subfunc;
			type = 'subfunc';
		}
		if (end !== -1 && end < newindex) {
			newindex = end;
			type = 'end';
		}
		if (script !== -1 && script < newindex) {
			newindex = script;
			type = 'script';
		}
		if (sentence !== -1 && sentence < newindex) {
			newindex = sentence;
			type = '%';
		}
		//将中间字符加入队列
		if (index < newindex) {
			current.list.push({ type: "text", value: text.substring(index, newindex) });
		}
		index = newindex;
		switch (type) {
			case 'include':
			case 'func':
			case 'subfunc':
			case 'script':
			case '%':
				//没有数据则直接返回
				if (!text.substr(index + 2, 1)) {
					break;
				}
				//获取标签信息
				let taginfo = parseTag(text, index + 2, { 'include': '/', 'func': '', 'subfunc': '', 'script': '`', '%': '%' }[type]);
				if (!taginfo) {
					//无信息表示数据无效
					current.list.push({ type: "text", value: "<" });
					index++;
				} else if (type === 'include') {
					//包含文件
					index = taginfo.index;
					let tag = { type, value: Script(taginfo.value) };
					current.list.push(tag);
				} else if (type === '%') {
					//表达式
					//设置新下标
					index = taginfo.index;
					let tag = { type: null, value: null };
					//获取首字符，进行进一步类型判断
					let ch = taginfo.value[0];
					//输出
					if (ch === "=") {
						tag.type = 'echo';tag.value = Script(taginfo.value.substr(1));
					}
					//脚本
					else {
							tag.type = 'script';tag.value = Script(taginfo.value);
						}
					//加入列表
					current.list.push(tag);
				} else if (type === 'script') {
					//表达式
					//设置新下标
					index = taginfo.index;
					let tag = { type: null, value: null };
					//获取首字符，进行进一步类型判断
					let ch = taginfo.value[0];
					if (ch === "=") {
						//输出
						tag.type = 'echo';
						tag.value = Script(taginfo.value.substr(1));
					} else if (ch === "`") {
						//不解析脚本
						let v = taginfo.value,
						    i = 1,
						    j = v.length - 1;
						while (v[i] === '`') {
							i++;
						}
						while (v[j] === '`') {
							j--;
						}
						if (j <= i) {
							break;
						}
						tag.type = 'sentence';
						tag.value = Script(taginfo.value.substr(i, j + 1));
					} else {
						//脚本
						tag.type = 'script';
						tag.value = Script(taginfo.value);
					}
					//加入列表
					current.list.push(tag);
				} else if (type === 'func' || type === 'subfunc') {
					//功能, 子功能
					//标签解析
					let funcInfo = parseFunc(taginfo.value);
					if (!funcInfo) {
						//标签解析失败
						current.list.push({ type: "text", value: "<" });
						index++;
					} else {
						index = taginfo.index;
						if (type === 'func') {
							//创建
							let tag = {
								type: 'func', parent: current, list: [],
								name: funcInfo.name, value: funcInfo.value,
								attr: funcInfo.attr,
								main: null, sub: []
							};
							tag.main = tag;
							current.list.push(tag);
							if (!taginfo.closed) {
								current = tag;
							}
						} else if (type === 'subfunc') {
							let tag = {
								list: [], parent: current.parent,
								name: funcInfo.name, value: funcInfo.value,
								attr: funcInfo.attr, main: current.main
							};
							current.main.sub.push(tag);
							delete current.main;
							delete current.parent;
							current = tag;
							if (taginfo.closed && current !== root) {
								let parent = current.parent;
								delete current.parent;
								delete current.main;
								current = parent;
							}
						}
					}
				} else {
					index = taginfo.index;
					let tag = { type: type, value: null };
					tag.value = Script(taginfo.value);
					current.list.push(tag);
				}
				break;
			case 'end':
				if (current !== root) {
					let parent = current.parent;
					delete current.parent;
					delete current.main;
					current = parent;
				}
				index += 3;
				break;
		}
	} while (subfunc !== -1 || func !== -1 || end !== -1 || include !== -1 || script !== -1 || sentence !== -1);
	return root.list;
}

function parseTag(text, begin, sign) {
	//位置: 主位置, 在字符串中, 引号, 代码, 反斜杠, 结束符
	let index = begin,
	    instr = false,
	    quote = 0,
	    code = 0,
	    slant = 0,
	    end = 0;
	if (sign) {
		sign += ">";
	} else {
		sign = ">";
	}
	do {
		if (quote !== -1) {
			quote = text.indexOf("\"", index);
		}
		if (slant !== -1) {
			slant = text.indexOf("\\", index);
		}
		if (code !== -1) {
			code = text.indexOf("`", index);
		}
		if (end !== -1) {
			end = text.indexOf(sign, index);
		}
		//选中的类型, 新的位置
		let type = 0,
		    newindex = text.length;
		if (quote !== -1 && quote < newindex) {
			newindex = quote;type = 'quote';
		}
		if (slant !== -1 && instr && slant < newindex) {
			newindex = slant;type = 'slant';
		}
		if (end !== -1 && !instr && end < newindex) {
			newindex = end;type = 'end';
		}
		if (code !== -1 && !instr && code < newindex) {
			newindex = code;type = 'code';
		}
		index = newindex + 1;
		switch (type) {
			case 'quote':
				instr = !instr;
				break;
			case 'slant':
				index++;
				break;
			case 'code':
				if (sign === "`>") {
					if (begin + 1 === index) {
						while (text[index] === "`") {
							index++;
						}
						break;
					}
					while (text[index] === "`" && index !== text.indexOf('`>', index)) {
						index++;
					}
					if (index !== text.indexOf(sign, index)) {
						return null;
					};
					end = index;
				} else {
					while (text[index] === "`") {
						index++;
					}
					index = text.indexOf("`", index);
					if (index === -1) {
						return null;
					}
					while (text[index] === "`") {
						index++;
					}
					break;
				}
			case 'end':
				if (sign === "`>" && begin + 1 === index) {
					break;
				}
				text = text.substring(begin, end);
				let closed = false;
				if (sign === '>' && text.substr(-1) === '/') {
					text = text.substr(0, text.length - 1);
					closed = true;
				}
				return { value: text, closed: closed, index: index + sign.length - 1 };
		}
	} while (end !== -1);
	return null;
}

function parseFunc(text) {

	//位置: 主位置, 属性位置, 在字符串中, 代码, 引号, 反斜杠, 空格, 制表符, 回车
	let index = 0,
	    attrindex = 0,
	    instr = false,
	    code = 0,
	    quote = 0,
	    slant = 0,
	    space = 0,
	    tab = 0,
	    enter = 0;
	//标签名, 值, 属性
	let name = '',
	    value,
	    attr = {};
	do {
		if (quote !== -1) {
			quote = text.indexOf("\"", index);
		}
		if (slant !== -1) {
			slant = text.indexOf("\\", index);
		}
		if (code !== -1) {
			code = text.indexOf("`", index);
		}
		if (space !== -1) {
			space = text.indexOf(" ", index);
		}
		if (tab !== -1) {
			tab = text.indexOf("	", index);
		}
		if (enter !== -1) {
			enter = text.indexOf("\n", index);
		}
		//选中的类型, 新的位置
		let type = 'space',
		    newindex = text.length;
		if (quote !== -1 && quote < newindex) {
			newindex = quote;type = 'quote';
		}
		if (slant !== -1 && instr && slant < newindex) {
			newindex = slant;type = 'slant';
		}
		if (code !== -1 && !instr && code < newindex) {
			newindex = code;type = 'code';
		}
		if (!instr) {
			if (space !== -1 && space < newindex) {
				newindex = space;type = 'space';
			}
			if (tab !== -1 && tab < newindex) {
				newindex = tab;type = 'space';
			}
			if (enter !== -1 && enter < newindex) {
				newindex = enter;type = 'space';
			}
		}
		index = newindex + 1;
		switch (type) {
			case 'quote':
				instr = !instr;
				break;
			case 'slant':
				index++;
				break;
			case 'code':
				while (text[index] === "`") {
					index++;
				};
				while (text[index] !== "`") {
					index++;
				};
				newindex = index;
				while (text[index] === "`") {
					index++;
				};
			case 'space':
				if (newindex === 0) {
					return null;
				}
				//获取单元数据
				let data = text.substring(attrindex, newindex);
				//去除空格，并设置下一属性起点
				while (text[index] === "\t" || text[index] === "\n" || text[index] === " ") {
					index++;
				};
				attrindex = index;
				//初步获取键值对
				let i = data.search("=");
				let k, v;
				if (i === -1) {
					k = data;
				} else {
					k = data.substring(0, i);v = data.substring(i + 1);
				}
				//处理键
				let o = true;
				if (!nameRegExp.test(k)) {
					o = false;
				}
				//处理值
				if (o && v) {
					if (v[0] === '`') {
						//脚本
						let e = false;
						if (v[1] === '`') {
							e = true;
						}
						let i = 1;
						while (v[i] === "`") {
							i++;
						};
						v = {
							value: Script(v.substring(i)),
							type: e ? "sentence" : "run",
							async get(scope) {
								if (this.type === "sentence") {
									return this.value;
								}
								return await this.value.exec(scope);
							}
						};
					} else {
						try {
							//特殊量
							v = { value: JSON.parse(v), async get() {
									return deepCopy(this.value);
								} };
						} catch (e) {
							//变量名
							if (v.search(/^[\u4E00-\u9FA5a-z_][\u4E00-\u9FA5a-z0-9_]*$/i) !== -1) {
								v = { value: v, type: "var", async get(scope) {
										return scope[this.value];
									} };
							} else {
								v = null;
							}
						}
					}
				}
				if (o & !v) {
					v = { async get() {
							return undefined;
						} };
				}
				//赋值处理
				if (!name) {
					if (o) {
						name = k;value = v;
					} else {
						return null;
					}
				} else if (o) {
					attr[k] = v;
				}
				break;
		}
	} while (quote !== -1 || space !== -1 || slant !== -1);
	return { name, value, attr };
}

function functmpl(p) {
	return new Functmpl(p);
}

functmpl.useType = useType;
functmpl.symbol = symbol;
functmpl.scope = _scope2.default;
functmpl.script = _script2.default;
functmpl.func = _func2.default;